﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;
using System.Web.Security;

namespace ScrewTurn.Wiki.Plugins.FormsAuthProvider
{
    //Must use IUsersStorageProviderV30 Interface and required Methods
    public class ScrewTurnFormsAuth: IUsersStorageProviderV30
    {
        private IUsersStorageProviderV30 m_StorageProvider;
        private const string HELP_HELP = "Configuration is set with the following parameters:<br/>AdminRoles - Comma seperated list of equivalent forms authentication admin roles<br/>UserRoles -  Comma seperated list of equivalent forms authentication user roles.";
        private IHostV30 m_Host;
        private string[] m_AdminRoles;
        private string[] m_UserRoles;

        #region Properties
        /// <summary>
        /// UserAccountsReadOnly Documentation ****************************************************
        /// http://www.screwturn.eu/Dev.WritingUsersStorageProvider.ashx?HL=authentication
        /// If the provider's UserAccountsReadOnly property returns true, the wiki will consider 
        /// user accounts handled by the provider as read-only, i.e. the wiki application will only 
        /// call GetUsers/GetUser/GetUserByEmail  and the login control methods, guaranteeing that 
        /// methods that alter users are never called. This setting is useful when integrating the user 
        /// store with another, external application.
        /// </summary>
        public bool UserAccountsReadOnly
        {
            get { return true; }
        }
        public bool UserGroupsReadOnly
        {
            get { return true; }
        }
        public bool GroupMembershipReadOnly
        {
            get { return true; }
        }
        public bool UsersDataReadOnly
        {
            get { return true; }
        }
        /// <summary>
        /// Plugin Help Text
        /// </summary>
        public string ConfigHelpHtml
        {
            get { return HELP_HELP; }
        }
 
        #endregion

        #region Base

        public void Init(IHostV30 host, string config)
        {
            m_Host = host;
            var provider = (from a in host.GetUsersStorageProviders(true)
                            where a.Information.Name != this.Information.Name
                            select a).FirstOrDefault();

            if (provider == null)
                throw new InvalidConfigurationException("This provider require an additional active storage provider for storing of active directory user information.");

            m_StorageProvider = provider;
            InitConfig(config);
        }
        /// <summary>
        /// Configures the plugin based on the configuration settings
        /// </summary>
        /// <param name="config"></param>
        private void InitConfig(string config)
        {
            if (string.IsNullOrEmpty(config))
                throw new InvalidConfigurationException("Config settings must be set before plugin can be used.");

            try
            {
                var configParts = config.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var configPart in configParts)
                {
                    var setting = configPart.Substring(0, configPart.IndexOf("="));
                    var value = configPart.Substring(configPart.IndexOf("=") + 1);
                    switch (setting.ToLower().Trim())
                    {
                        case "AdminRoles":
                            m_AdminRoles = value.ToString().Split(',');
                            break;
                        case "UserRoles":
                            m_UserRoles = value.ToString().Split(',');
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new InvalidConfigurationException("The configuration is invalid.", ex);
            }
        }
        /// <summary>
        /// Ignored
        /// </summary>
        public void Shutdown()
        {
            m_StorageProvider.Shutdown();
        }

        /// <summary>
        /// Plugin Information
        /// TODO return and complete
        /// </summary>
        public ComponentInformation Information
        {
            get { return new ComponentInformation("FormsAuthenticationProvider", "Sam Stange", "1.0", "http://www.screwturn.eu", ""); }
        }

        

        #endregion

        /// REGION: ManageUserAccount Documentation ****************************************************
        /// http://www.screwturn.eu/Dev.WritingUsersStorageProvider.ashx?HL=authentication
        /// GetUsers, GetUser, GetUserByEmail, AddUser, ModifyUser, and RemoveUser are 
        /// required inteface methods
        #region ManageUserAccounts

        //Shoot your website in the head method. Not implemented here.
        public UserInfo[] GetUsers()
        {
            return new UserInfo[] { };
        }

        public UserInfo GetUser(string Username)
        {
            var user = m_StorageProvider.GetUser(Username);
            
            if (user != null)
                return user;

            MembershipUser mu = Membership.GetUser(Username);

            if (mu != null)
            {
                UserInfo ui = new UserInfo(mu.UserName, mu.UserName, mu.Email, mu.IsApproved, mu.CreationDate, this);


                var displayName = string.Empty;
                var emailAddress = string.Empty;
                var adminGroup = false;
                var userGroup = false;

                displayName = mu.UserName;
                emailAddress = mu.Email;

                foreach (string role in m_AdminRoles)
                {
                    if (Roles.IsUserInRole(role))
                       adminGroup = true;
                }

                foreach (string role in m_UserRoles)
                {
                    if (Roles.IsUserInRole(role))
                        userGroup = true;
                }

                var userGroups = new List<string>();

                if (adminGroup)
                    userGroups.Add("Administrators");
                if (userGroup)
                    userGroups.Add("Users");

                user = m_StorageProvider.AddUser(Username, displayName, "jdzs98duadj2918j9sdjasd", emailAddress, true, DateTime.Now);
                user = m_StorageProvider.SetUserMembership(user, userGroups.ToArray());
                return user;
            }
            else
                return null;
        }

        public UserInfo GetUserByEmail(string Email)
        {
            MembershipUser mu = Membership.GetUser(Membership.GetUserNameByEmail(Email));

            if (mu != null)
                return new UserInfo(mu.UserName, mu.UserName, mu.Email, mu.IsApproved, mu.CreationDate, this);
            else
                return null;
        }

        

        /// <summary>
        /// Not Implemented
        /// </summary>
        public UserInfo AddUser(string username, string displayName, string password, string email, bool active, DateTime dateTime)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Not Implemented
        /// </summary>
        public UserInfo ModifyUser(UserInfo user, string newDisplayName, string newPassword, string newEmail, bool newActive)
        {
            throw new NotImplementedException();
        }

        public bool RemoveUser(UserInfo user)
        {
            throw new NotImplementedException("RemoveUser Method is not supported. User management is handled else where");
        }
        #endregion

        #region User Groups and Membership

        public UserGroup[] GetUserGroups()
        {
            return new UserGroup[] { };
        }

        //Not implemented methods. Property UserGroupsReadOnly is set to true, thereby 
        //adding,modifying, and removing groups is not implemented or used.
        public UserGroup AddUserGroup(string name, string description)
        {
            throw new NotImplementedException("AddUserGroup Method is not supported. User management is handled else where");
        }
        public UserGroup ModifyUserGroup(UserGroup group, string description)
        {
            throw new NotImplementedException("ModifyUserGroup Method is not supported. User management is handled else where");
        }
        public bool RemoveUserGroup(UserGroup groupName)
        {
            throw new NotImplementedException("RemoveUserGroup Method is not supported. User management is handled else where");
        }
        public UserInfo SetUserMembership(UserInfo user, string[] groups)
        {
            throw new NotImplementedException("SetUserMembership Method is not supported. User management is handled else where");
        }
        #endregion

        
        /// REGION: LOGIN CONTROL Documentation ****************************************************
        /// http://www.screwturn.eu/Dev.WritingUsersStorageProvider.ashx?HL=authentication
        /// TestAccount, TryManualLogin, TryAutoLogin, NotifyCookieLogin, NotifyLogout are 
        /// required inteface methods

        #region Login Control
        public bool TestAccount(UserInfo user, string password)
        { return false; }
        public UserInfo TryManualLogin(string username, string password)
        {
            if (Membership.ValidateUser(username, password))
            {
                return GetUser(username);
            }
            else
                return null;
        }
        /// <summary>
        /// Tries to log the user in automagically
        /// </summary>
        public UserInfo TryAutoLogin(System.Web.HttpContext context)
        {

            try
            {

                if (!context.User.Identity.IsAuthenticated)
                    return null;

                var username = context.User.Identity.Name.Substring(context.User.Identity.Name.IndexOf("\\") + 1);
                return GetUser(username);

            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// Not Implemented - Passed Directly to the IUsersStorageProviderV30
        /// </summary>
        public void NotifyCookieLogin(UserInfo user)
        {

            m_StorageProvider.NotifyCookieLogin(user);

        }

        /// <summary>
        /// Not Implemented - Passed Directly to the IUsersStorageProviderV30
        /// </summary>
        public void NotifyLogout(UserInfo user)
        {

            m_StorageProvider.NotifyLogout(user);

        }
        #endregion

        #region UserData
        /// <summary>
        /// Not Implemented - Passed Directly to the IUsersStorageProviderV30
        /// </summary>
        public bool StoreUserData(UserInfo user, string key, string value)
        {

            return m_StorageProvider.StoreUserData(user, key, value);

        }

        /// <summary>
        /// Not Implemented - Passed Directly to the IUsersStorageProviderV30
        /// </summary>
        public string RetrieveUserData(UserInfo user, string key)
        {

            return m_StorageProvider.RetrieveUserData(user, key);

        }

        /// <summary>
        /// Not Implemented - Passed Directly to the IUsersStorageProviderV30
        /// </summary>
        public IDictionary<string, string> RetrieveAllUserData(UserInfo user)
        {

            return m_StorageProvider.RetrieveAllUserData(user);

        }
        /// <summary>
        /// Not Implemented - Passed Directly to the IUsersStorageProviderV30
        /// </summary>
        public IDictionary<UserInfo, string> GetUsersWithData(string key)
        {

            return m_StorageProvider.GetUsersWithData(key);

        }
        #endregion

    }
}
